﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;

namespace Is.Core
{
    internal static class ExpressionExtension
    {
        public static IEnumerable<Expression> GetExpressions<T, K>(this Expression<Func<T, K>> expression)
        {
            List<Expression> expressionList = new List<Expression>();
            Expression currentNode = expression.Body;
            while (currentNode.NodeType != ExpressionType.Parameter)
            {
                switch (currentNode.NodeType)
                {
                    case ExpressionType.Convert:
                        //// Skip the convert from the expression: expressionList.Add(((UnaryExpression)currentNode).Operand);
                        currentNode = ((UnaryExpression)currentNode).Operand;
                        break;
                    case ExpressionType.MemberAccess:
                        MemberExpression memberExpression;
                        memberExpression = (currentNode.NodeType == ExpressionType.MemberAccess ? (MemberExpression)currentNode : (MemberExpression)((UnaryExpression)currentNode).Operand);
                        if (memberExpression.Member.MemberType != MemberTypes.Property && memberExpression.Member.MemberType != MemberTypes.Field)
                        {
                            throw new InvalidOperationException("The member '" + memberExpression.Member.Name + "' is a " + memberExpression.Member.MemberType.ToString() + " but a Property or Field is expected.");
                        }
                        expressionList.Add(memberExpression);
                        currentNode = memberExpression.Expression;
                        break;
                    case ExpressionType.Call:
                        MethodCallExpression methodCallExpression = (MethodCallExpression)currentNode;
                        expressionList.Add(methodCallExpression);
                        currentNode = methodCallExpression.Object;
                        break;
                    default:
                        throw new InvalidOperationException("The expression NodeType '" + currentNode.NodeType.ToString() + "' is not supported, expected MemberAccess, Convert, or Call.");
                        break;
                }
            }
            //// skip the root (Parameter) from expression: expressionList.Add((ParameterExpression)currentNode);
            expressionList.Reverse();
            return expressionList;
        }
    }
}
